#include "ReiniciarProceso.h"

#include <stdexcept>
#include <unistd.h>
#include <sys/wait.h>
#include <gtkmm/menuitem.h>
#include <gtkmm/messagedialog.h>

#include "Socket.h"


ReiniciarProceso::ReiniciarProceso(Glib::RefPtr<Gtk::Builder> b, std::string nomMenu, Configuraciones** cfg,
	std::string nomProg)
{
	Gtk::MenuItem* mi = 0;
	b->get_widget(nomMenu, mi);
	if (!mi) throw std::runtime_error("No se encontró "+nomMenu);

	mi->signal_activate().connect( sigc::mem_fun(*this, &ReiniciarProceso::resetProceso) );

	this->_ppConfig = cfg;
	this->_nomServer = nomProg;
}


ReiniciarProceso::~ReiniciarProceso(){
}


void ReiniciarProceso::resetProceso(){
	// Si no hay puerto para detenerlo no es posible hacerlo
	if (*this->_ppConfig == NULL){

		Gtk::MessageDialog md("Error al tratar de reiniciar el servidor");
		md.set_secondary_text("No se puede ejecutar la acción requerida");

		md.run();
	} else {
		detenerServidor( (*this->_ppConfig)->nroPuertoCtrl );
		sleep(2);	// Da tiempo al servidor de apagarse (2 segs)
		iniciarServidor(this->_nomServer);
	}
}


void ReiniciarProceso::detenerServidor(unsigned short int nroPuerto){
	try {
		// El servidor siempre esta en la misma maquina (o deberia)
		ClientSocket cs("127.0.0.1", nroPuerto);

		// "q" es la señal de apagado del servidor
		char q = 'q';
		cs.send(static_cast<void*>( &q ), sizeof(q));
		cs.close();

	} catch (SocketException& sex){
		Gtk::MessageDialog md("Error al tratar de detener el servidor");
		md.set_secondary_text("No fue posible realizar la conexión");

		md.run();
	}
}


void ReiniciarProceso::iniciarServidor(std::string nombreProg){
	try {
		// Se crea un nuevo proceso hijo
		int fork_rv = fork();
		if (fork_rv == 0){

			// Se crea un proceso nieto
			fork_rv = fork();
			if (fork_rv == 0){
				// El nieto ejecuta el proceso señalado
				execl(nombreProg.c_str(), nombreProg.c_str(), 0);
				_exit(1);

			} else if (fork_rv == -1){
				throw std::runtime_error("Error al parir el nuevo proceso nieto");
			}

			// Todo salio bien
			_exit(0);

		} else if (fork_rv != -1){
			// El padre espera al proceso hijo (deberia salir rapido)
			int status;
			waitpid(fork_rv, &status, 0);

		} else if (fork_rv == -1){
			throw std::runtime_error("Error al parir el nuevo proceso hijo");
		}

	} catch (std::runtime_error& rte){
		// De alguna forma fallo la creación del nuevo proceso
		Gtk::MessageDialog md("Error al tratar de iniciar el servidor");
		md.set_secondary_text(rte.what());

		md.run();
	}
}


